using UnityEngine;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Net;
using SimpleJSON;

public static class SmartSync
{
	internal static class ConfigNode
	{
		public const string TIMESTAMP_NAME = "timestampName";
		public const string REQUEST_METHOD = "requestMethod";
		public const string REQUEST_NAME   = "requestName";
	};

	/*
	internal class QoocoWebClient : WebClient
	{
		protected override WebRequest GetWebRequest (System.Uri address)
		{
			WebRequest w = base.GetWebRequest(address);
			w.Timeout = 10 * 60 * 100;
			return w;
		}
	};*/

	private static JSONNode s_configNode;
	private static Dictionary<string, Dictionary<string, string>> s_localizationStrings;
	private static ServerInfo s_serverInfo;
	private static string userLocalizationLanguage = "en_US";


	//SPID=1005
	//UserId=209035
	private static string s_urlFormat = "http://cdp.qooco.com/service/sync.jsp?SPID={0}&UserId={1}&v=4";

	static SmartSync()
	{
		s_configNode = JSON.Parse((Resources.Load("syncConfig") as TextAsset).text);
	}

	private static bool Store(string data)
	{
		try
		{
			JSONNode responseNode = JSON.Parse(data);
			
			if (responseNode["localizationStrings"] != null)
			{
				s_localizationStrings = ParseLocalizationStings(responseNode["localizationStrings"][userLocalizationLanguage]);
			}
			
			if (responseNode["serverInfo"] != null)
			{
				s_serverInfo = ParseServerInfo(responseNode["serverInfo"]);
			}

			return true;
		}
		catch(System.Exception)
		{
			Debug.Log("parse error");
			return false;
		}
	}

	private static void Post(string url, string report, System.Action<bool, string> finishCallback)
	{
		System.Threading.ThreadPool.QueueUserWorkItem(delegate
		{
			using (var client = new WebClient())
			{
				var valForPost = new NameValueCollection();
				if (report != "")
				{
					valForPost["report"] = report;
				}

				try
				{
					var response = client.UploadValues(url, valForPost);
					if (finishCallback != null)
					{
						finishCallback(true, Encoding.Default.GetString(response) );
					}
				}
				catch (System.Exception)
				{
					if (finishCallback != null)
					{
						finishCallback(false, string.Empty);
					}
				}
			}
		});
	}

	private static Dictionary<string, Dictionary<string, string>> ParseLocalizationStings (JSONNode localizationJson) 
	{
		Dictionary<string, Dictionary<string, string>> localizationDictionary = new Dictionary<string, Dictionary<string, string>>();
		foreach (string dictionaryName in localizationJson.Keys) 
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			JSONNode dictionaryWords = localizationJson[dictionaryName]["strings"];
			foreach(string wordKey in dictionaryWords.Keys)
			{
				string word = dictionaryWords[wordKey];
				dictionary.Add(wordKey, word);
			}
			
			if (dictionary.Keys.Count != 0)
			{
				localizationDictionary.Add(dictionaryName, dictionary);
			}
		}
		
		return localizationDictionary;
	}

	private static ServerInfo ParseServerInfo (JSONNode serverInfoNode) 
	{
		ServerInfo serverInfo = new ServerInfo();
		if (serverInfoNode["qasarHost"] != null)
		{
			serverInfo.qasarHost = serverInfoNode["qasarHost"];
		}

		if (serverInfoNode["snsHost"] != null)
		{
			serverInfo.snsHost = serverInfoNode["snsHost"];
		}

		if (serverInfoNode["apiHost"] != null)
		{
			serverInfo.apiHost = serverInfoNode["apiHost"];
		}

		if (serverInfoNode["mediaHost"] != null)
		{
			serverInfo.mediaHost = serverInfoNode["mediaHost"];
		}

		if (serverInfoNode["imageFolders"] != null)
		{
			JSONNode imageFolders = serverInfoNode["imageFolders"];
			Dictionary<string, string> imageFoldersDictionary = new Dictionary<string, string>();
			foreach(string folderName in imageFolders.Keys)
			{
				imageFoldersDictionary.Add(folderName, imageFolders[folderName]);
			}
			serverInfo.imageFolders = imageFoldersDictionary;
		}

		if (serverInfoNode["languages"] != null)
		{
			JSONNode languages = serverInfoNode["languages"].AsArray;
			Dictionary<string, string>[] languagesArr = new Dictionary<string, string>[languages.Count];

			for (int i = 0; i < languages.Count; i++)
			{
				JSONNode node = languages[i];
				Dictionary <string, string> dictionary = new Dictionary<string, string>();
				dictionary.Add("name", node["name"]);
				dictionary.Add("locale", node["locale"]);
				languagesArr[i] = dictionary;
			}
			serverInfo.languages = languagesArr;
		}
		return serverInfo;
	}

	public static void Sync(string SPID, string userId, RequestInfo request, System.Action<bool> finishCallback)
	{
		Sync(SPID, userId, new RequestInfo[]{request}, finishCallback);
	}

	public static void Sync(string SPID, string userId, RequestInfo[] requests, System.Action<bool> finishCallback)
	{
		// TODO: improve error reporting.
		string url = string.Format(s_urlFormat, SPID, userId);
		string postData = "";

		foreach (var req in requests)
		{
			var node = s_configNode["dataToSync"][req.GetKey()];

			if (string.CompareOrdinal(node[ConfigNode.REQUEST_METHOD], "byLocaleAndCollection") == 0)
			{
				var r = (LocaleAndCollectinRequestInfo)req;	
				JSONClass jsonCollectionKeys = new JSONClass();
				
				var collectionKeys = r.GetCollectionKeys();
				for (int i = 0; i < collectionKeys.Length; ++i)
				{
					jsonCollectionKeys.Add(collectionKeys[i], new JSONData(0));
				}

				string requestName = node[ConfigNode.REQUEST_NAME];
				JSONClass jsonReq    = new JSONClass();
				JSONClass jsonLocale = new JSONClass();
				JSONData  userLocale = new JSONData(r.GetLocale());
				jsonLocale.Add(r.GetLocale(), jsonCollectionKeys);
				jsonReq.Add(requestName, jsonLocale);
				jsonReq.Add("userLocale", userLocale);
				
				postData = jsonReq.ToString();
			} 
			else 
			{
				int timestamp = 0;
				string timeStampName = node[ConfigNode.TIMESTAMP_NAME];
				string timestampFormat = "&{0}={1}";
				url += string.Format(timestampFormat, timeStampName, timestamp);
			}
		}

		Post(url, postData, (succeed, receivedData) =>
		{
			bool hasDataStored = false;
			if (succeed)
			{
				Debug.Log("post request was successful.");
				hasDataStored = Store(receivedData);
			}
			if (finishCallback != null)
			{
				if (!hasDataStored)
				{
					Debug.Log("store data has failed.");
				}

				finishCallback(hasDataStored);
			}
		});
	}

	public static Dictionary<string, string> GetLocalizedStrings(string dictionaryName)
	{
		Dictionary<string, string> dictionary = null;
		s_localizationStrings.TryGetValue(dictionaryName, out dictionary);
		return dictionary;
	}

	public static ServerInfo GetServerInfo()
	{
		return s_serverInfo;
	}
};

